﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ComponentModel;
using System.Windows;
using Telerik.Windows.Controls;
using Telerik.Windows.Data;
using Telerik.Windows.Controls.GridView;
using System.Runtime.Serialization;
using System.IO;
using System.IO.IsolatedStorage;


namespace MContracts.View
{
    public sealed class RadGridViewSettings
    {
        public RadGridViewSettings()
        {
            //
        }

        public class RadGridViewApplicationSettings : Dictionary<string, object>
        {
            private RadGridViewSettings settings;

            private DataContractSerializer serializer = null;

            public RadGridViewApplicationSettings()
            {
                //
            }

            public RadGridViewApplicationSettings(RadGridViewSettings settings)
            {
                this.settings = settings;

                var types = new List<Type>
                    {
                        typeof (List<ColumnSetting>),
                        typeof (List<FilterSetting>),
                        typeof (List<GroupSetting>),
                        typeof (List<SortSetting>),
                        typeof (List<PropertySetting>)
                    };

                this.serializer = new DataContractSerializer(typeof(RadGridViewApplicationSettings), types);
            }

            public string PersistID
            {
                get
                {
                    if (!ContainsKey("PersistID") && settings.grid != null)
                    {
                        this["PersistID"] = settings.grid.Name;
                    }

                    return (string)this["PersistID"];
                }
            }

            public int FrozenColumnCount
            {
                get
                {
                    if (!ContainsKey("FrozenColumnCount"))
                    {
                        this["FrozenColumnCount"] = 0;
                    }

                    return (int)this["FrozenColumnCount"];
                }
                set
                {
                    this["FrozenColumnCount"] = value;
                }
            }

            public List<ColumnSetting> ColumnSettings
            {
                get
                {
                    if (!ContainsKey("ColumnSettings"))
                    {
                        this["ColumnSettings"] = new List<ColumnSetting>();
                    }

                    return (List<ColumnSetting>)this["ColumnSettings"];
                }
            }

            public List<SortSetting> SortSettings
            {
                get
                {
                    if (!ContainsKey("SortSettings"))
                    {
                        this["SortSettings"] = new List<SortSetting>();
                    }

                    return (List<SortSetting>)this["SortSettings"];
                }
            }

            public List<GroupSetting> GroupSettings
            {
                get
                {
                    if (!ContainsKey("GroupSettings"))
                    {
                        this["GroupSettings"] = new List<GroupSetting>();
                    }

                    return (List<GroupSetting>)this["GroupSettings"];
                }
            }

            public List<FilterSetting> FilterSettings
            {
                get
                {
                    if (!ContainsKey("FilterSettings"))
                    {
                        this["FilterSettings"] = new List<FilterSetting>();
                    }

                    return (List<FilterSetting>)this["FilterSettings"];
                }
            }

            public void Reload()
            {
                try
                {
                    using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForAssembly())
                    {
                        using (var stream = new IsolatedStorageFileStream(PersistID, FileMode.OpenOrCreate, file))
                        {
                            if (stream.Length > 0)
                            {
                                var loaded = (RadGridViewApplicationSettings)serializer.ReadObject(stream);

                                FrozenColumnCount = loaded.FrozenColumnCount;

                                ColumnSettings.Clear();
                                foreach (ColumnSetting cs in loaded.ColumnSettings)
                                {
                                    ColumnSettings.Add(cs);
                                }

                                FilterSettings.Clear();
                                foreach (FilterSetting fs in loaded.FilterSettings)
                                {
                                    FilterSettings.Add(fs);
                                }

                                GroupSettings.Clear();
                                foreach (GroupSetting gs in loaded.GroupSettings)
                                {
                                    GroupSettings.Add(gs);
                                }

                                SortSettings.Clear();
                                foreach (SortSetting ss in loaded.SortSettings)
                                {
                                    SortSettings.Add(ss);
                                }
                            }
                        }
                    }
                }
                catch
                {

                }
            }

            public void Reset()
            {
                try
                {
                    using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForAssembly())
                    {
                        file.DeleteFile(PersistID);
                    }
                }
                catch
                {
                    //
                }
            }

            public void Save()
            {
                try
                {
                    using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForAssembly())
                    {
                        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(PersistID, FileMode.Create, file))
                        {
                            serializer.WriteObject(stream, this);
                        }
                    }
                }
                catch
                {
                    //
                }
            }
        }

        private RadGridView grid = null;

        public RadGridViewSettings(RadGridView grid)
        {
            this.grid = grid;
        }

        public static readonly DependencyProperty IsEnabledProperty
           = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(RadGridViewSettings),
                new PropertyMetadata(new PropertyChangedCallback(OnIsEnabledPropertyChanged)));

        public static bool GetIsEnabled(DependencyObject dependencyObject)
        {
            return (bool)dependencyObject.GetValue(IsEnabledProperty);
        }

        public static void SetIsEnabled(DependencyObject dependencyObject, bool enabled)
        {
            dependencyObject.SetValue(IsEnabledProperty, enabled);
        }

        private static void OnIsEnabledPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            RadGridView grid = dependencyObject as RadGridView;
            if (grid != null)
            {
                if ((bool)e.NewValue)
                {
                    RadGridViewSettings settings = new RadGridViewSettings(grid);
                    settings.Attach();
                }
            }
        }

        public void LoadState()
        {
            try
            {
                Settings.Reload();
            }
            catch
            {
                Settings.Reset();
            }

            if (this.grid != null)
            {
                IsChanging = true;
                try
                {
                    grid.FrozenColumnCount = Settings.FrozenColumnCount;

                    LoadColumnLayoutSettings();

                    using (grid.DeferRefresh())
                    {
                        LoadSortSettings();

                        LoadGroupSettings();

                        LoadFilterSettings();
                    }
                }
                finally
                {
                    IsChanging = false;
                }
            }
        }

        private void LoadFilterSettings()
        {
            if (Settings.FilterSettings.Count > 0)
            {
                foreach (FilterSetting setting in Settings.FilterSettings)
                {
                    FilterSetting currentSetting = setting;

                    GridViewDataColumn matchingColumn =
                        (from column in grid.Columns.OfType<GridViewDataColumn>()
                         where column.DataMemberBinding!=null && column.DataMemberBinding.Path.Path == currentSetting.PropertyName
                         select column).FirstOrDefault();

                    if (matchingColumn != null)
                    {
                        var cfd = new ColumnFilterDescriptor(matchingColumn);

                        if (setting.Filter1 != null && setting.Filter1.Member != null)
                        {
                            cfd.FieldFilter.Filter1.Member = setting.Filter1.Member;
                            cfd.FieldFilter.Filter1.Operator = setting.Filter1.Operator;
                            cfd.FieldFilter.Filter1.Value = setting.Filter1.Value;
                        }

                        if (setting.Filter2 != null && setting.Filter2.Member != null)
                        {
                            cfd.FieldFilter.Filter2.Member = setting.Filter2.Member;
                            cfd.FieldFilter.Filter2.Operator = setting.Filter2.Operator;
                            cfd.FieldFilter.Filter2.Value = setting.Filter2.Value;
                        }

                        foreach (FilterDescriptorSetting fds in setting.SelectedDistinctValues)
                        {
                            var fd = new Telerik.Windows.Data.FilterDescriptor();
                            fd.Member = fds.Member;
                            fd.Operator = fds.Operator;
                            fd.Value = fds.Value;
                            cfd.DistinctFilter.FilterDescriptors.Add(fd);
                        }

                        this.grid.FilterDescriptors.Add(cfd);
                    }
                }
            }
        }

        private void LoadGroupSettings()
        {
            if (Settings.GroupSettings.Count > 0)
            {
                grid.GroupDescriptors.Clear();

                foreach (GroupSetting setting in Settings.GroupSettings)
                {
                    ColumnGroupDescriptor d = new ColumnGroupDescriptor();

                    d.Column = (from c in grid.Columns.OfType<GridViewBoundColumnBase>()
                                where c.GetDataMemberName() == setting.PropertyName
                                select c).FirstOrDefault();
                    d.SortDirection = setting.SortDirection;
                   
                    if (d.Column != null)
                        grid.GroupDescriptors.Add(d);
                }
            }
        }

        private void LoadSortSettings()
        {
            if (Settings.SortSettings.Count > 0)
            {
                grid.SortDescriptors.Clear();

                foreach (SortSetting setting in Settings.SortSettings)
                {
                    ColumnSortDescriptor d = new ColumnSortDescriptor();
                    d.Column = (from c in grid.Columns.OfType<GridViewBoundColumnBase>()
                                where c.GetDataMemberName() == setting.PropertyName
                                select c).FirstOrDefault();
                    d.SortDirection = setting.SortDirection;
                    if (d.Column != null)
                        grid.SortDescriptors.Add(d);
                }
            }
        }

        private void LoadColumnLayoutSettings()
        {
            if (Settings.ColumnSettings.Count > 0)
            {
                foreach (ColumnSetting setting in Settings.ColumnSettings)
                {
                    ColumnSetting currentSetting = setting;

                    GridViewDataColumn column = (from c in grid.Columns.OfType<GridViewDataColumn>()
                                                 where c.UniqueName == currentSetting.UniqueName
                                                 select c).FirstOrDefault();

                    if (column != null)
                    {
                        if (currentSetting.DisplayIndex != null)
                        {
                            column.DisplayIndex = currentSetting.DisplayIndex.Value;
                        }

                        if (setting.Width != null)
                        {
                            column.Width = new GridViewLength(setting.Width.Value);
                        }
                    }
                }
            }
        }

        public void ResetState()
        {
            Settings.Reset();
        }

        public void SaveState(bool saveFilters=true, bool saveGroups=true, bool saveSort=true)
        {
            Settings.Reset();

            if (grid != null)
            {
                if (grid.Columns != null)
                {
                    Settings.ColumnSettings.Clear();

                    foreach (GridViewColumn column in grid.Columns)
                    {
                        if (column is GridViewDataColumn)
                        {
                            
                            GridViewDataColumn dataColumn = (GridViewDataColumn)column;
                           
                            if (dataColumn.DataMemberBinding != null)
                            {
                                ColumnSetting setting = new ColumnSetting();
                                setting.PropertyName = dataColumn.DataMemberBinding.Path.Path;
                                    setting.UniqueName = dataColumn.UniqueName;
                                setting.Header = dataColumn.Header;
                                setting.Width = dataColumn.ActualWidth;
                                setting.DisplayIndex = dataColumn.DisplayIndex;

                                Settings.ColumnSettings.Add(setting);
                            }
                        }
                    }
                }
                if (saveFilters)
                if (grid.FilterDescriptors != null)
                {
                    Settings.FilterSettings.Clear();

                    foreach (IColumnFilterDescriptor cfd in grid.FilterDescriptors.OfType<IColumnFilterDescriptor>())
                    {
                        FilterSetting setting = new FilterSetting();

                        if (cfd.FieldFilter.Filter1.Value != Telerik.Windows.Data.FilterDescriptor.UnsetValue)
                        {
                            setting.Filter1 = new FilterDescriptorSetting();
                            setting.Filter1.Member = cfd.FieldFilter.Filter1.Member;
                            setting.Filter1.Operator = cfd.FieldFilter.Filter1.Operator;
                            setting.Filter1.Value = cfd.FieldFilter.Filter1.Value;
                        }

                        if (cfd.FieldFilter.Filter2.Value != Telerik.Windows.Data.FilterDescriptor.UnsetValue)
                        {
                            setting.Filter2 = new FilterDescriptorSetting();
                            setting.Filter2.Member = cfd.FieldFilter.Filter2.Member;
                            setting.Filter2.Operator = cfd.FieldFilter.Filter2.Operator;
                            setting.Filter2.Value = cfd.FieldFilter.Filter2.Value;
                        }

                        foreach (Telerik.Windows.Data.FilterDescriptor fd in cfd.DistinctFilter.FilterDescriptors.OfType<Telerik.Windows.Data.FilterDescriptor>())
                        {
                            if (fd.Value == Telerik.Windows.Data.FilterDescriptor.UnsetValue)
                            {
                                continue;
                            }

                            FilterDescriptorSetting fds = new FilterDescriptorSetting();
                            fds.Member = fd.Member;
                            fds.Operator = fd.Operator;
                            fds.Value = fd.Value;
                            setting.SelectedDistinctValues.Add(fds);
                        }

                        setting.PropertyName = cfd.Column.DataMemberBinding.Path.Path;

                        Settings.FilterSettings.Add(setting);
                    }
                }
                if (saveSort)
                if (grid.SortDescriptors != null)
                {
                    Settings.SortSettings.Clear();

                    foreach (ColumnSortDescriptor d in grid.SortDescriptors.OfType<ColumnSortDescriptor>())
                    {
                        SortSetting setting = new SortSetting();

                        setting.PropertyName = ((GridViewDataColumn)d.Column).GetDataMemberName();
                        setting.SortDirection = d.SortDirection;

                        Settings.SortSettings.Add(setting);
                    }
                }

                if (saveGroups)
                if (grid.GroupDescriptors != null)
                {
                    Settings.GroupSettings.Clear();

                    foreach (ColumnGroupDescriptor d in grid.GroupDescriptors.OfType<ColumnGroupDescriptor>())
                    {
                        GroupSetting setting = new GroupSetting();

                        setting.PropertyName = ((GridViewDataColumn)d.Column).GetDataMemberName();
                        setting.SortDirection = d.SortDirection;

                        Settings.GroupSettings.Add(setting);
                    }
                }

                Settings.FrozenColumnCount = grid.FrozenColumnCount;
            }

            Settings.Save();
        }

        private void Attach()
        {
            if (this.grid != null)
            {
                this.grid.LayoutUpdated += new EventHandler(LayoutUpdated);
                this.grid.Loaded += Loaded;
                Application.Current.Exit += Current_Exit;
            }
        }

        void Current_Exit(object sender, EventArgs e)
        {
            SaveState();
        }

        void Loaded(object sender, EventArgs e)
        {
            LoadState();
        }

        void LayoutUpdated(object sender, EventArgs e)
        {
            if (grid.Parent == null)
            {
                SaveState();
            }
        }

        private RadGridViewApplicationSettings gridViewApplicationSettings = null;

        private RadGridViewApplicationSettings CreateRadGridViewApplicationSettingsInstance()
        {
            return new RadGridViewApplicationSettings(this);
        }

        private RadGridViewApplicationSettings Settings
        {
            get
            {
                if (gridViewApplicationSettings == null)
                {
                    gridViewApplicationSettings = CreateRadGridViewApplicationSettingsInstance();
                }
                return gridViewApplicationSettings;
            }
        }

        public bool IsChanging 
        { get; private set; }
    }

    public class PropertySetting
    {
        string _PropertyName;
        public string PropertyName
        {
            get
            {
                return _PropertyName;
            }
            set
            {
                _PropertyName = value;
            }
        }
    }

    public class SortSetting : PropertySetting
    {
        ListSortDirection _SortDirection;
        public ListSortDirection SortDirection
        {
            get
            {
                return _SortDirection;
            }
            set
            {
                _SortDirection = value;
            }
        }
    }

    public class GroupSetting : PropertySetting
    {
        ListSortDirection? _SortDirection;
        public ListSortDirection? SortDirection
        {
            get
            {
                return _SortDirection;
            }
            set
            {
                _SortDirection = value;
            }
        }
    }

    public class FilterSetting : PropertySetting
    {
        List<FilterDescriptorSetting> _SelectedDistinctValues;
        public List<FilterDescriptorSetting> SelectedDistinctValues
        {
            get
            {
                if (_SelectedDistinctValues == null)
                {
                    _SelectedDistinctValues = new List<FilterDescriptorSetting>();
                }
                return _SelectedDistinctValues;
            }
        }

        FilterDescriptorSetting _Filter1;
        public FilterDescriptorSetting Filter1
        {
            get
            {
                return _Filter1;
            }
            set
            {
                _Filter1 = value;
            }
        }

        FilterDescriptorSetting _Filter2;
        public FilterDescriptorSetting Filter2
        {
            get
            {
                return _Filter2;
            }
            set
            {
                _Filter2 = value;
            }
        }
    }

    public class FilterDescriptorSetting
    {
        string _Member;
        public string Member
        {
            get
            {
                return _Member;
            }
            set
            {
                _Member = value;
            }
        }

        Telerik.Windows.Data.FilterOperator _Operator;
        public Telerik.Windows.Data.FilterOperator Operator
        {
            get
            {
                return _Operator;
            }
            set
            {
                _Operator = value;
            }
        }

        object _Value;
        public object Value
        {
            get
            {
                return _Value;
            }
            set
            {
                _Value = value;
            }
        }

        bool _IsCaseSensitive;
        public bool IsCaseSensitive
        {
            get
            {
                return _IsCaseSensitive;
            }
            set
            {
                _IsCaseSensitive = value;
            }
        }
    }

    public class ColumnSetting : PropertySetting
    {
        string _UniqueName;
        public string UniqueName
        {
            get
            {
                return _UniqueName;
            }
            set
            {
                _UniqueName = value;
            }
        }

        object _Header;
        public object Header
        {
            get
            {
                return _Header;
            }
            set
            {
                _Header = value;
            }
        }

        double? _Width;
        public double? Width
        {
            get
            {
                return _Width;
            }
            set
            {
                _Width = value;
            }
        }

        int? _DisplayIndex;
        public int? DisplayIndex
        {
            get
            {
                return _DisplayIndex;
            }
            set
            {
                _DisplayIndex = value;
            }
        }
    }
}
